#ifndef SYNC_REDIS_CONNECTION_H
#define SYNC_REDIS_CONNECTION_H

#include <muduo/base/Logging.h>

#include <boost/shared_ptr.hpp>

#include <hiredis.h>

using namespace muduo;

namespace sdfs
{
namespace redis
{

class RedisReply
{
public:
	RedisReply(redisReply* reply):reply_(reply)
	{

	}
	~RedisReply()
	{
		LOG_DEBUG << "~RedisReply";
		freeReplyObject(reply_);
		reply_ = NULL;
	}

	int size()
	{
		return reply_->elements;
	}

	int type()
	{
		return reply_->type;
	}

	bool assertType(int type)
	{
		assert(reply_->type == type);
	}

	int getIntAt(int idx)
	{
		assert(reply_->type == REDIS_REPLY_ARRAY);
		assert(size() > idx);
		return reply_->element[idx]->integer;
	}

	muduo::string getStrAt(int idx)
	{
		assert(reply_->type == REDIS_REPLY_ARRAY);
		assert(size() > idx);
		return reply_->element[idx]->str;
	}

	muduo::string getStr()
	{
		assertType(REDIS_REPLY_STRING);
		return reply_->str;
	}

	int getInteger()
	{
		assertType(REDIS_REPLY_INTEGER);
		return reply_->integer;
	}

	bool isNull()
	{
		return REDIS_REPLY_NIL == reply_->type ? true : false;
	}

	bool isArray()
	{
		return REDIS_REPLY_ARRAY == reply_->type ? true : false;
	}
private:
	redisReply* reply_;
};

typedef boost::shared_ptr<RedisReply> RedisReplyPtr;

class SyncRedisConnector
{
public:
	SyncRedisConnector(const muduo::string& ip, int port):
		context_(NULL), ip_(ip), port_(port)
	{

	}
	~SyncRedisConnector()
	{
		LOG_DEBUG << "~SyncRedisConnector";
		if(context_ != NULL)
			disconnect();
	}

	void connect()
	{
		LOG_DEBUG << "connect: "<< ip_ << ":" << port_;
		context_ = redisConnect(ip_.c_str(), port_);
		if (context_ == NULL) {
			LOG_ERROR <<"Connection error: can't allocate redis context";
		} else if (context_->err) {
			LOG_ERROR << "Connection error: " << context_->errstr;
		}
	}

	void disconnect()
	{
		LOG_DEBUG << "disconnect redis";
		// redisReply *reply;

		// reply = static_cast<redisReply*>(redisCommand(context_,"FLUSHDB"));
		// assert(reply != NULL);
		// freeReplyObject(reply);

		/* Free the context as well. */
		redisFree(context_);
		context_=NULL;
	}

	RedisReplyPtr command(const muduo::string& cmd)
	{
		redisReply* p = static_cast<redisReply*>(redisCommand(context_, cmd.c_str()));
		RedisReplyPtr reply(new RedisReply(p));
		return reply;
	}


	/* data */
private:
	redisContext *context_;
	muduo::string ip_;
	int port_;
};

typedef boost::shared_ptr<SyncRedisConnector> SyncRedisConnectorPtr;

}
}

#endif